#include <algorithm>
#include <chrono>
#include <cstdarg>
#include <cstdio>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <string.h>

#include "logger.h"

#ifdef _WIN32
    #include <io.h>
    #include <windows.h>

    #define access _access
#else
    #include <sys/stat.h>
    #include <unistd.h>

#endif

logger* logger::m_instance = nullptr;

logger::logger() :
    m_log_file(nullptr),
    m_log_level(OS_DEBUG),
    m_max_file_size(10 * 1024 * 1024)  // 默认10MB
{
    // 默认日志文件路径
    m_file_path = "application.log";
}

logger::~logger()
{
    if (m_log_file && m_log_file->is_open()) {
        m_log_file->close();
    }
}

logger* logger::instance()
{
    static std::mutex mutex;
    if (!m_instance) {
        std::lock_guard<std::mutex> locker(mutex);
        if (!m_instance) {
            m_instance = new logger;
        }
    }
    return m_instance;
}

void logger::release()
{
    static std::mutex mutex;
    std::lock_guard<std::mutex> locker(mutex);
    if (m_instance) {
        delete m_instance;
        m_instance = nullptr;
    }
}

void logger::setLogLevel(log_level_e level)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    m_log_level = level;
}

log_level_e logger::getLogLevel()
{
    return m_log_level;
}

void logger::setLogFile(const std::string& file)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    m_file_path = file;

    if (m_log_file && m_log_file->is_open()) {
        m_log_file->close();
    }

    m_log_file = std::unique_ptr<std::ofstream>(new std::ofstream(m_file_path, std::ios::out | std::ios::app));
    if (!m_log_file->is_open()) {
        std::cerr << "Failed to open log file: " << m_file_path << std::endl;
        m_log_file.reset();
        return;
    }
}

void logger::setMaxFileSize(size_t size)
{
    std::lock_guard<std::mutex> locker(m_mutex);
    m_max_file_size = size;
}

void logger::log(log_level_e level, const std::string& message, const char* file, int line)
{
    // 检查日志级别
    if (level < m_log_level) {
        return;
    }

    std::lock_guard<std::mutex> locker(m_mutex);

    // 获取当前时间
    auto now = std::chrono::system_clock::now();
    auto time_t = std::chrono::system_clock::to_time_t(now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

    // 使用 strftime 替代 std::put_time 来兼容 C++11
    char time_buffer[20];
    std::strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", std::localtime(&time_t));
    std::stringstream timestamp;
    timestamp << time_buffer << ":" << std::setfill('0') << std::setw(3) << ms.count();

    // 构建日志消息
    std::string logMessage;
    if (file && strlen(file) > 0) {
        std::string fileName = file;
        size_t pos = fileName.find_last_of("/\\");
        if (pos != std::string::npos) {
            fileName = fileName.substr(pos + 1);
        }
        logMessage = timestamp.str() + "[" + levelToString(level) + "] " + message + " (" + fileName + ":" +
                     std::to_string(line) + ")";
    } else {
        logMessage = timestamp.str() + "[" + levelToString(level) + "] " + message;
    }

    // 输出到控制台（带颜色）
    std::string colorCode = levelToColor(level);

#ifdef _WIN32
    // Windows控制台颜色设置
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    WORD color = 7;  // 默认白色

    if (level == OS_DEBUG) {
        color = 7;  // 白色
    } else if (level == OS_INFO) {
        color = 10;  // 绿色
    } else if (level == OS_WARNING) {
        color = 14;  // 黄色
    } else if (level == OS_ERROR || level == OS_FATAL) {
        color = 12;  // 红色
    }

    SetConsoleTextAttribute(hConsole, color);
    std::cout << logMessage << std::endl;
    SetConsoleTextAttribute(hConsole, 7);  // 恢复默认颜色
#else
    // Linux/Unix控制台颜色设置
    std::cout << colorCode << logMessage << "\033[0m" << std::endl;  // 重置颜色
#endif

    // 输出到文件
    if (m_log_file && m_log_file->is_open()) {
        *m_log_file << logMessage << std::endl;
        m_log_file->flush();

        // 检查文件大小，如果需要则滚动日志
        // 注意：这里需要重新打开文件来获取大小
        std::ifstream ifs(m_file_path, std::ios::ate | std::ios::binary);
        if (ifs.is_open() && ifs.tellg() > static_cast<std::streampos>(m_max_file_size)) {
            rotateLog();
        }
    }
}

void logger::log2(log_level_e level, const std::string& message)
{
    // 检查日志级别
    if (level < m_log_level) {
        return;
    }

    std::lock_guard<std::mutex> locker(m_mutex);

    // 构建日志消息
    std::string logMessage = " " + message;

    // 输出到控制台（带颜色）
    std::string colorCode = levelToColor(level);

#ifdef _WIN32
    // Windows控制台颜色设置
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    WORD color = 7;  // 默认白色

    if (level == OS_DEBUG) {
        color = 7;  // 白色
    } else if (level == OS_INFO) {
        color = 10;  // 绿色
    } else if (level == OS_WARNING) {
        color = 14;  // 黄色
    } else if (level == OS_ERROR || level == OS_FATAL) {
        color = 12;  // 红色
    }

    SetConsoleTextAttribute(hConsole, color);
    std::cout << logMessage;
    SetConsoleTextAttribute(hConsole, 7);  // 恢复默认颜色
#else
    // Linux/Unix控制台颜色设置
    std::cout << colorCode << logMessage << "\033[0m";  // 重置颜色
#endif

    // 输出到文件
    if (m_log_file && m_log_file->is_open()) {
        *m_log_file << logMessage << std::endl;
        m_log_file->flush();

        // 检查文件大小，如果需要则滚动日志
        std::ifstream ifs(m_file_path, std::ios::ate | std::ios::binary);
        if (ifs.is_open() && ifs.tellg() > static_cast<std::streampos>(m_max_file_size)) {
            rotateLog();
        }
    }
}
void logger::log3(log_level_e level, const std::string& message, const char* file, const char* func, int line)
{
    // 检查日志级别
    if (level < m_log_level) {
        return;
    }

    std::lock_guard<std::mutex> locker(m_mutex);

    // 获取当前时间
    auto now = std::chrono::system_clock::now();
    auto time_t = std::chrono::system_clock::to_time_t(now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

    // 使用 strftime 替代 std::put_time 来兼容 C++11
    char time_buffer[20];
    std::strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", std::localtime(&time_t));
    std::stringstream timestamp;
    timestamp << time_buffer << ":" << std::setfill('0') << std::setw(3) << ms.count();

    // 构建日志消息
    std::string logMessage;
    if (file && strlen(file) > 0) {
        std::string fileName = file;
        std::string func_str = func;
        size_t pos = fileName.find_last_of("/\\");
        if (pos != std::string::npos) {
            fileName = fileName.substr(pos + 1);
        }
        logMessage = timestamp.str() + "[" + levelToString(level) + "] " + message + " (" + fileName + ":->" +
                     func_str + ":" + std::to_string(line) + ")";
    } else {
        logMessage = timestamp.str() + "[" + levelToString(level) + "] " + message;
    }

    // 输出到控制台（带颜色）
    std::string colorCode = levelToColor(level);

#ifdef _WIN32
    // Windows控制台颜色设置
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    WORD color = 7;  // 默认白色

    if (level == OS_DEBUG) {
        color = 7;  // 白色
    } else if (level == OS_INFO) {
        color = 10;  // 绿色
    } else if (level == OS_WARNING) {
        color = 14;  // 黄色
    } else if (level == OS_ERROR || level == OS_FATAL) {
        color = 12;  // 红色
    }

    SetConsoleTextAttribute(hConsole, color);
    std::cout << logMessage << std::endl;
    SetConsoleTextAttribute(hConsole, 7);  // 恢复默认颜色
#else
    // Linux/Unix控制台颜色设置
    std::cout << colorCode << logMessage << "\033[0m" << std::endl;  // 重置颜色
#endif

    // 输出到文件
    if (m_log_file && m_log_file->is_open()) {
        *m_log_file << logMessage << std::endl;
        m_log_file->flush();

        // 检查文件大小，如果需要则滚动日志
        // 注意：这里需要重新打开文件来获取大小
        std::ifstream ifs(m_file_path, std::ios::ate | std::ios::binary);
        if (ifs.is_open() && ifs.tellg() > static_cast<std::streampos>(m_max_file_size)) {
            rotateLog();
        }
    }
}
void logger::logFormatted(log_level_e level, const char* file, int line, const char* format, ...)
{
    // 检查日志级别
    if (level < m_log_level) {
        return;
    }

    // 格式化消息
    char buffer[1024];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);

    // 调用常规日志函数
    log(level, std::string(buffer), file, line);
}
void logger::logFormatted3(log_level_e level, const char* file, const char* func, int line, const char* format, ...)
{
    // 检查日志级别
    if (level < m_log_level) {
        return;
    }

    // 格式化消息
    char buffer[1024];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);

    // 调用常规日志函数
    log3(level, std::string(buffer), file, func, line);
}

void logger::logFormatted2(log_level_e level, const char* format, ...)
{
    // 检查日志级别
    if (level < m_log_level) {
        return;
    }

    // 格式化消息
    char buffer[1024];
    va_list args;
    va_start(args, format);
    vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);

    // 调用常规日志函数
    log2(level, std::string(buffer));
}

std::string logger::levelToString(log_level_e level)
{
    switch (level) {
        case OS_DEBUG: return "D";
        case OS_INFO: return "I";
        case OS_WARNING: return "W";
        case OS_ERROR: return "E";
        case OS_FATAL: return "F";
        default: return "U";
    }
}

std::string logger::levelToColor(log_level_e level)
{
    switch (level) {
        case OS_DEBUG: return "\033[0;37m";    // 白色
        case OS_INFO: return "\033[0;32m";     // 绿色
        case OS_WARNING: return "\033[1;33m";  // 黄色
        case OS_ERROR: return "\033[0;31m";    // 红色
        case OS_FATAL: return "\033[1;31m";    // 亮红色
        default: return "\033[0m";              // 默认
    }
}

void logger::rotateLog()
{
    if (!m_log_file || !m_log_file->is_open()) {
        return;
    }

    m_log_file->flush();
    m_log_file->close();

    // 重命名当前日志文件

    // 查找可用的备份文件名
    int counter = 1;
    std::string newName;
    do {
        newName = m_file_path + "." + std::to_string(counter++);
    } while (access(newName.c_str(), F_OK) == 0);

    rename(m_file_path.c_str(), newName.c_str());

    // 重新打开日志文件
    m_log_file = std::unique_ptr<std::ofstream>(new std::ofstream(m_file_path, std::ios::out | std::ios::app));
    if (!m_log_file->is_open()) {
        std::cerr << "Failed to reopen log file after rotation" << std::endl;
        m_log_file.reset();
        return;
    }
}

void printMemory(const std::string& info)
{
    if (logger::instance()->getLogLevel() > OS_INFO) {
        return;
    }

#ifdef __linux__
    // 使用/proc文件系统获取内存信息
    std::string state_file = "/proc/" + std::to_string(getpid()) + "/status";
    std::ifstream statusFile(state_file);
    if (statusFile.is_open()) {
        std::string line;
        while (std::getline(statusFile, line)) {
            if (line.substr(0, 6) == "VmRSS:") {
                std::istringstream iss(line);
                std::string key, value, unit;
                iss >> key >> value >> unit;

                try {
                    long memoryKB = std::stol(value);
                    double memoryMB = memoryKB / 1024.0;
                    LOGW("%s,当前消耗内存: %lf MB", info.c_str(), memoryMB);
                } catch (const std::exception&) {
                    // 转换失败，忽略
                }
                break;
            }
        }
        statusFile.close();
    }
#endif
}